﻿using System;
using System.Threading;
using FrameWork.Core.Enum;
using System.Collections.Generic;
using FrameWork.Core.Chain.Entitys;
using FrameWork.Core.Chain.Invengo;

namespace FrameWork.Core.Aggregator
{
    /// <summary>
    /// 流程聚合类
    /// </summary>
    /// <typeparam name="C"></typeparam>
    /// <typeparam name="P"></typeparam>
    /// <typeparam name="R"></typeparam>
    public class ChainAggregator<C, P, R> : IChainAggregator<C, P, R>
        where P : InvengoProcess<R>, new()
        where R : ProcessDataBase, new()
        where C : InvengoChainEngine<P>, new()
    {
        private readonly Dictionary<Type, InvengoChainEngine<P>> Chains = new Dictionary<Type, InvengoChainEngine<P>>();
        /// <summary>
        /// 立即执行
        /// </summary>
        /// <param name="record"></param>
        public P CreateAndRun(R record)
        {
            C newChain = null;
            lock (Chains)
            {
                if (!Chains.TryGetValue(typeof(C), out InvengoChainEngine<P> outChain))
                {
                    newChain = new C();
                    Chains[typeof(C)] = newChain;
                }
                else
                    newChain = (C)outChain;
            }
            var process = new P()
            {
                Record = record,
                AutoReset = new AutoResetEvent(false),
                State = EnumProcessState.Ready
            };
            newChain.Run(process);
            return process;
        }
        /// <summary>
        /// 同步排队执行
        /// </summary>
        /// <param name="record"></param>
        public void CreateAndRunWithQueue(R record)
        {
            C newChain = null;
            lock (Chains)
            {
                if (!Chains.TryGetValue(typeof(C), out InvengoChainEngine<P> outChain))
                {
                    newChain = new C();
                    Chains[typeof(C)] = newChain;
                }
                else
                    newChain = (C)outChain;
            }
            newChain.RunWithQueue(new P()
            {
                Record = record,
                AutoReset = new AutoResetEvent(false),
                State = EnumProcessState.Ready
            });
        }
        /// <summary>
        /// 同步执行,同一时只执行一个任务
        /// </summary>
        /// <param name="record"></param>
        public void CreateAndRunWithMonopoly(R record)
        {
            C newChain = null;
            lock (Chains)
            {
                if (!Chains.TryGetValue(typeof(C), out InvengoChainEngine<P> outChain))
                {
                    newChain = new C();
                    Chains[typeof(C)] = newChain;
                }
                else
                    newChain = (C)outChain;
            }
            newChain.RunWithMonopoly(new P()
            {
                Record = record,
                AutoReset = new AutoResetEvent(false),
                State = EnumProcessState.Ready
            });
        }
        /// <summary>
        /// 异步执行
        /// </summary>
        /// <param name="record"></param>
        public void CreateAndRunWithAsync(R record)
        {
            C newChain = null;
            lock (Chains)
            {
                if (!Chains.TryGetValue(typeof(C), out InvengoChainEngine<P> outChain))
                {
                    newChain = new C();
                    Chains[typeof(C)] = newChain;
                }
                else
                    newChain = (C)outChain;
            }
            newChain.RunWithAsync(new P()
            {
                Record = record,
                AutoReset = new AutoResetEvent(false),
                State = EnumProcessState.Ready
            });
        }
    }
}